/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package trim.gui.testing;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import trim.common.Format;
import trim.common.inputdata.FormatOrder;
import trim.common.Material;
import trim.common.inputdata.MaterialStock;
import trim.common.inputdata.InputData;
import trim.scripting.interfaces.ITestGenerator;

/**
 * Класс предназначенный для генерации тестов
 *
 * Created 25.01.2009 13:54:22
 * @author Саковнич Дмитрий
 */
public class TestsGenerator implements ITestGenerator<Material,Format>
{
private static final Random rand=new Random(System.currentTimeMillis());
  public TestsGenerator()
  {
  }

  /**
   * Генерация набора тестов.В сгенерированном наборе тестов
   * будут тесты для каждого количества различных форматов от minFormats до maxFormats
   * и для каждого количества различных материалов от minMaterials до maxMaterials
   * @param minFormats минимальное количество различных форматов
   * @param maxFormats максимальное количество различных форматов
   * @param maxFormatCount максимальное количество рулонов по каждому формату
   * @param minMaterials минимальное количество различных материалов
   * @param maxMaterials максимальное количество различных материалов
   * @param maxMaterialsCount максимальное количество заготовок по каждому материалу
   * @param testsPerSettings количество тестов для каждой настройки
   * @return набор сгенерированных тестов
   */
  @Override
  public List<InputData> generateTests(int minFormats,
    int maxFormats,int maxFormatCount,
    int minMaterials,int maxMaterials,
    int maxMaterialsCount,int testsPerSettings)
  {

    List<Material> materials=getMaterialsList();
    List<FormatStatistic> formats=getFormatsList();
    if(materials.size()==0)
      materials.add(new Material(100));
    if(formats.size()==0)
      formats.add(new FormatStatistic(10,1));


    return generateTestsProc(minFormats,maxFormats,maxFormatCount,minMaterials,maxMaterials,
      maxMaterialsCount,testsPerSettings,formats,materials);
  }

  /**
   * Генерация набора тестов.В сгенерированном наборе тестов
   * будут тесты для каждого количества различных форматов от minFormats до maxFormats
   * и для каждого количества различных материалов от minMaterials до maxMaterials
   * @param minFormats минимальное количество различных форматов
   * @param maxFormats максимальное количество ращличных форматов
   * @param maxFormatCount максимальное количество рулонов по каждому формату
   * @param minMaterials минимальное количество различных материалов
   * @param maxMaterials максимальное количество различных материалов
   * @param maxMaterialsCount максимальное количество заготовок по каждому материалу
   * @param testsPerSettings количество тестов для каждой настройки
   * @param formats форматы из которых будут генерироваться тесты
   * @param materials материалы из которых будут генерироваться тесты
   * @return набор сгенерированных тестов
   */
  @Override
  public List<InputData> generateTests(
    int minFormats,int maxFormats,int maxFormatCount,
    int minMaterials,int maxMaterials,int maxMaterialsCount,
    int testsPerSettings,
    List<Format> formats,List<Material> materials)
  {
    List<FormatStatistic> fs=new ArrayList(formats.size());
    for(Format f:formats)
      fs.add(new FormatStatistic(f,1));
    
    return generateTestsProc(minFormats,maxFormats,maxFormatCount,minMaterials,maxMaterials,
      maxMaterialsCount,testsPerSettings,fs,materials);
  }

  private List<InputData> generateTestsProc(
    int minFormats,int maxFormats,int maxFormatCount,
    int minMaterials,int maxMaterials,int maxMaterialsCount,
    int testsPerSettings,
    List<FormatStatistic> formats,List<Material> materials)
  {
    List<InputData> res=new ArrayList();
    for(int fc=maxFormats;fc>=minFormats;fc--)
    {
      for(int mc=maxMaterials;mc>=minMaterials;mc--)
      {
        for(int i=0;i<testsPerSettings;i++)
          res.add(genTest(fc,maxFormatCount,mc,maxMaterialsCount,formats,materials));
      }
    }
    return res;
  }

  private static InputData genTest(int fc,int maxFormatCount,int mc,
    int maxMaterialsCount,List<FormatStatistic> formats,List<Material> materials)
  {
    boolean[] isused=new boolean[formats.size()];
    InputData res=new InputData();
    Map m=new HashMap();
    int countSum=0;
    for(FormatStatistic f:formats)
      countSum+=f.count;
    for(int i=0;i<fc;i++)
    {
      int k=0;
      int z=rand.nextInt(countSum);
      int n=0;
      int c=0;
      int j=0;
      while(c<z+1&&j<formats.size())
      {
        if(!isused[j])
          c+=formats.get(j).count;
        j++;
      }
    isused[j-1]=true;
      Format f=formats.get(j-1).format;
      countSum-=formats.get(j-1).count;
      //while(m.get(f.getLength())!=null&&(k++<20))
      //  f=formats.get(rand.nextInt(formats.size()));
      m.put(f.getLength(),f);
      res.getFormatOrderList().add(new FormatOrder(f,
        rand.nextInt(maxFormatCount)+1));
    }
    m.clear();
    for(int i=0;i<mc;i++)
    {
      int k=0;
      Material f=materials.get(rand.nextInt(materials.size()));
      while(m.get(f.getLength())!=null&&(k++<20))
        f=materials.get(rand.nextInt(materials.size()));
      m.put(f.getLength(),f);
      res.getMaterialStockList().add(new MaterialStock(f,
        rand.nextInt(maxMaterialsCount)+1));
    }
    return res;
  }

  /**
   * Чтение списка добустимых форматов из файла
   * @return
   */
  private static List<FormatStatistic> getFormatsList()
  {
    BufferedReader reader=null;

    List<FormatStatistic> res=null;
    File f=new File("."+File.separator+"formats.csv");
    if(!f.exists())
      return new ArrayList();
    try
    {
      reader=new BufferedReader(new FileReader(f));
      String s;
      boolean b=true;
      int len=0;
      int cnt=0;
      Map<Integer,Integer> formats=new HashMap();
      while((s=reader.readLine())!=null)
      {
        String[] as=s.split("[ \t]");
        len=Integer.parseInt(as[0]);
        cnt=Integer.parseInt(as[1]);
        formats.put(len,cnt);
      }
      res=new ArrayList(formats.size());
      for(Integer format:formats.keySet())
        res.add(new FormatStatistic(format.intValue(),formats.get(format).intValue()));
      return res;
    }catch(Exception ex)
    {
      ex.printStackTrace();
      return new ArrayList();
    }finally
    {
      try
      {
        reader.close();
      }catch(IOException ex)
      {
        ex.printStackTrace();
        return new ArrayList();
      }
    }
  }

  /**
   * Чтение списка допустимых материалов из файла
   * @return
   */
  private static List<Material> getMaterialsList()
  {
    BufferedReader reader=null;

    List<Material> res=null;
    File f=new File("."+File.separator+"materials.csv");
    if(!f.exists())
      return new ArrayList();
    try
    {
      reader=new BufferedReader(new FileReader(f));
      String s;
      boolean b=true;
      int len=0;
      Map<Integer,Integer> materials=new HashMap();
      while((s=reader.readLine())!=null)
      {
        if(s.trim().equals(""))
          continue;
        String[] as=s.split("[ \t]");
        len=Integer.parseInt(as[0]);
        materials.put(len,len);
      }
      res=new ArrayList(materials.size());
      for(Integer material:materials.keySet())
        res.add(new Material(material.intValue()));
      return res;
    }catch(Exception ex)
    {
      ex.printStackTrace();
      return new ArrayList();
    }finally
    {
      try
      {
        reader.close();
      }catch(IOException ex)
      {
        ex.printStackTrace();
        return new ArrayList();
      }
    }
  }


  private static class FormatStatistic
  {
    private Format format;
    private int count;

    public FormatStatistic(Format format,int count)
    {
      this.format=format;
      this.count=count;
    }

    public FormatStatistic(int format,int count)
    {
      this.format=new Format(format);
      this.count=count;
    }

    public int getCount()
    {
      return count;
    }

    public void setCount(int count)
    {
      this.count=count;
    }

    public Format getFormat()
    {
      return format;
    }

    public void setFormat(Format format)
    {
      this.format=format;
    }

  }
}
